package com.baoteng.image.transformation;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.support.annotation.NonNull;
import android.support.annotation.Px;

import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import com.bumptech.glide.load.resource.bitmap.TransformationUtils;

import java.security.MessageDigest;

/**
 * 图片添加倒影
 */
public class ReflexBlurTransformation extends BitmapTransformation {

    private static final int DEFAULT_RADIUS = 24;
    private static final int DEFAULT_PADDING = 35;

    /**
     * 倒影占比
     */
    private static final float DEFAULT_REFLECT_PERCENT = 0.35f;
    private Context mContext;
    /**
     * 圆角的半径
     */
    @Px
    private int mRadius;
    /**
     * 倒影距图片的间距
     */
    @Px
    private int mPadding;
    /**
     * 倒影高度
     */
    private int mReflectHeight;
    /**
     * 倒影占原图高度的比例
     */
    private float mReflectPercent;
    /**
     * 矩形图片宽
     */
    @Px
    private int mRectangleWidth;
    /**
     * 矩形图片高
     */
    @Px
    private int mRectangleHeight;

    /**
     * 是否有边框
     */
    private boolean mHasBorder;
    /**
     * 是否有高光
     */
    private boolean mHasHighlight;

    private ReflexBlurTransformation(Context context) {
        this.mContext = context.getApplicationContext();
        this.mRadius = DEFAULT_RADIUS;
        this.mPadding = DEFAULT_PADDING;
        this.mReflectPercent = DEFAULT_REFLECT_PERCENT;
    }

    public static Builder with(Context context) {
        return new Builder(context);
    }

    public static class Builder {
        private ReflexBlurTransformation reflexBlurTransformation;


        Builder(Context context) {
            reflexBlurTransformation = new ReflexBlurTransformation(context);
        }

        /**
         * 正方形图片边长
         */
        public Builder sideLength(@Px int sideLength) {
            reflexBlurTransformation.mRectangleWidth = sideLength;
            reflexBlurTransformation.mRectangleHeight = sideLength;
            return this;
        }

        /**
         * 长方形方形图片边长
         */
        public Builder rectangle(@Px int width, int height) {
            reflexBlurTransformation.mRectangleWidth = width;
            reflexBlurTransformation.mRectangleHeight = height;
            return this;
        }

        /**
         * 倒影高度，优先级比{@link Builder#reflectPercent(float)}高
         */
        public Builder reflectHeight(@Px int reflectHeight) {
            reflexBlurTransformation.mReflectHeight = reflectHeight;
            return this;
        }

        /**
         * 反射倒影站原图高度的百分比,优先级比{@link Builder#reflectHeight(int)}低
         *
         * @param percent 倒影高度占原图高度的百分比
         * @return builder
         */
        public Builder reflectPercent(float percent) {
            reflexBlurTransformation.mReflectPercent = percent;
            return this;
        }

        /**
         * 圆角的半径
         */
        public Builder radius(@Px int mRadius) {
            reflexBlurTransformation.mRadius = mRadius;
            return this;
        }

        /**
         * 倒影距图片的间距
         */
        public Builder padding(@Px int padding) {
            reflexBlurTransformation.mPadding = padding;
            return this;
        }

        /**
         * 给原图片增加边框
         */
        public Builder border() {
            reflexBlurTransformation.mHasBorder = true;
            return this;
        }

        /**
         * 给原图片增加高光
         */
        public Builder highlight() {
            reflexBlurTransformation.mHasHighlight = true;
            return this;
        }

        /**
         * 创建TF对象
         *
         * @return Tf对象
         */
        public ReflexBlurTransformation create() {
            if (reflexBlurTransformation.mReflectHeight > reflexBlurTransformation.mRectangleHeight) {
                throw new RuntimeException("倒影比与原图边长还长了");
            }
            if (reflexBlurTransformation.mReflectHeight == 0) {
                reflexBlurTransformation.mReflectHeight = (int) (reflexBlurTransformation.mRectangleHeight * reflexBlurTransformation.mReflectPercent);
            }
            return reflexBlurTransformation;
        }
    }

//    private WeakReference<Drawable> mHighlightDrawableRef;

//    private Drawable getHighlightDrawable(int width, int height) {
//        Drawable dr;
//        if (mHighlightDrawableRef == null
//                || (dr = mHighlightDrawableRef.get()) == null) {
//            mHighlightDrawableRef = new WeakReference<>(
//                    dr = mContext.getDrawable(R.drawable.highlight));
//        }
//        dr.setBounds(0, 0, width, height);
//        return dr;
//    }

//    private WeakReference<Drawable> mBorderDrawableRef;

//    private Drawable getBorderDrawable(int width, int height) {
//        Drawable dr;
//        if (mBorderDrawableRef == null
//                || (dr = mBorderDrawableRef.get()) == null) {
//            mBorderDrawableRef = new WeakReference<>(
//                    dr = mContext.getDrawable(R.drawable.border));
//        }
//        dr.setBounds(0, 0, width, height);
//        return dr;
//    }

    private Paint mReverseOverlayPaint;

    private Paint getReverseOverlayPaint() {
        if (mReverseOverlayPaint == null) {
            Paint paint = new Paint();
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
            mReverseOverlayPaint = paint;
        }
        return mReverseOverlayPaint;
    }

    @Override
    protected Bitmap transform(@NonNull BitmapPool pool,
                               @NonNull Bitmap toTransform,
                               int outWidth, int outHeight) {
        // 倒影的高度
        int reflectHeight = mReflectHeight;
        if (reflectHeight <= 0 && mReflectPercent > 0f) {
            reflectHeight = (int) (outHeight * mReflectPercent);
        }
        int oriWidth;// 原图宽度
        int oriHeight;// 原图高度
        if (mRectangleWidth > 0 && mRectangleHeight > 0) {
            oriWidth = mRectangleWidth;
            oriHeight = mRectangleHeight;
        } else {
            oriWidth = outWidth;
            oriHeight = outHeight - reflectHeight - mPadding;
        }
        // 【原图像】
        Bitmap oriBmp = pool.get(oriWidth, oriHeight, toTransform.getConfig());
        Canvas oriCanvas = new Canvas(oriBmp);
        Matrix oriM = new Matrix();
        oriM.setScale(
                (float) oriWidth / toTransform.getWidth(), (float) oriHeight / toTransform.getHeight(),
                0, 0);
        oriCanvas.drawBitmap(toTransform, oriM, null);
        if (mRadius > 0) {
            oriBmp = TransformationUtils.roundedCorners(pool, oriBmp, mRadius);
        }
//        // 绘制高光
//        if (mHasHighlight) {
//            getHighlightDrawable(oriWidth, oriHeight).draw(oriCanvas);
//        }
//        // 外边框
//        if (mHasBorder) {
//            getBorderDrawable(oriWidth, oriHeight).draw(oriCanvas);
//        }

        //【原图的倒影图像】
        Bitmap reverseBmp = pool.get(oriWidth, reflectHeight, Bitmap.Config.ARGB_8888);
        Canvas reverseCanvas = new Canvas(reverseBmp);
        reverseCanvas.scale(1, -1,
                reverseBmp.getWidth() / 2, reverseBmp.getHeight() / 2);
        Rect src = new Rect(
                0, oriBmp.getHeight() - reflectHeight,
                oriBmp.getWidth(), oriBmp.getHeight());
        Rect dst = new Rect(0, 0, reverseBmp.getWidth(), reverseBmp.getHeight());
        reverseCanvas.drawBitmap(oriBmp, src, dst, null);
        // 倒影遮罩
        Paint paint = getReverseOverlayPaint();
        LinearGradient shader = new LinearGradient(
                0, 0,
                0, reverseBmp.getHeight(),
                Color.TRANSPARENT, 0x60ffffff, Shader.TileMode.CLAMP);
        paint.setShader(shader);
        reverseCanvas.drawRect(0, 0, reverseBmp.getWidth(), reverseBmp.getHeight(), paint);

        // 最终输出的图像
        Bitmap retBmp = pool.get(outWidth, outHeight, Bitmap.Config.ARGB_8888);
        Canvas retCanvas = new Canvas(retBmp);
        retCanvas.drawBitmap(oriBmp, 0, 0, null);
        retCanvas.drawBitmap(reverseBmp, 0, oriBmp.getHeight() + mPadding, null);

        // 临时的图像使用完后,可以重新加到缓存里复用
        pool.put(oriBmp);
        pool.put(reverseBmp);

        return retBmp;
    }

    private String mID;
    private byte[] mIDBytes;

    private String getCacheID() {
        if (mID == null) {
            mID = join("_",
                    getClass().getName(),
                    mRadius,
                    mPadding,
                    mReflectHeight,
                    mReflectPercent,
                    mRectangleWidth,
                    mRectangleHeight,
                    mHasBorder,
                    mHasHighlight);
        }
        return mID;
    }

    private byte[] getCacheIDBytes() {
        if (mIDBytes == null) {
            mIDBytes = getCacheID().getBytes(Key.CHARSET);
        }
        return mIDBytes;
    }

    public static String join(CharSequence delimiter, Object... elements) {
        if (delimiter == null || elements == null)
            return null;
        final StringBuilder sb = new StringBuilder();
        for (final Object element : elements) {
            sb.append(element).append(delimiter);
        }
        if (sb.length() > 0) {
            return sb.substring(0, sb.length() - delimiter.length());
        }
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        return (o instanceof ReflexBlurTransformation)
                && getCacheID().equals(((ReflexBlurTransformation) o).getCacheID());
    }

    @Override
    public int hashCode() {
        return getCacheID().hashCode();
    }

    @Override
    public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
        messageDigest.update(getCacheIDBytes());
    }
}
